﻿// MIT License
// 开源地址：https://gitee.com/co1024/AbcMvc
// Copyright (c) 2021-2022 1024
// Abc.Mvc=Furion+EF+SqlSugar+Pear layui admin.

using Abc.Base;

using Furion;
using Furion.DatabaseAccessor;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System.Linq.Expressions;

namespace Abc.EntityFramework.Core
{
    [AppDbContext("DbConnectionString")]
    public class DefaultDbContext : AppDbContext<DefaultDbContext>, IModelBuilderFilter
    {
        public DefaultDbContext(DbContextOptions<DefaultDbContext> options) : base(options)
        {
            EnabledEntityChangedListener = true;//启用实体数据更改监听
        }

        /// <summary>
        /// 设置最小日期时间
        /// </summary>
        private DateTimeOffset minDateTimeOffset = Convert.ToDateTime("1900-01-01");

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // optionsBuilder.UseExceptionProcessor();
            base.OnConfiguring(optionsBuilder);
        }

        //public DbSet<SysLogAudit> AutidLogs { get; set; }

        #region 全局筛选器

        /// <summary>
        /// 构建之后
        /// </summary>
        /// <param name="modelBuilder"></param>
        /// <param name="entityBuilder"></param>
        /// <param name="dbContext"></param>
        /// <param name="dbContextLocator"></param>
        public void OnCreated(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            var expression = BuilderIsDeleteLambdaExpression(entityBuilder);
            if (expression == null) return;

            entityBuilder.HasQueryFilter(expression);
        }

        /// <summary>
        /// 构建之前
        /// </summary>
        /// <param name="modelBuilder"></param>
        /// <param name="entityBuilder"></param>
        /// <param name="dbContext"></param>
        /// <param name="dbContextLocator"></param>
        public void OnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
        }

        /// <summary>
        /// 构建 u => EF.Property<bool>(u, "IsDeleted") == false 表达式
        /// </summary>
        /// <param name="entityBuilder"></param>
        /// <returns></returns>
        private LambdaExpression BuilderIsDeleteLambdaExpression(EntityTypeBuilder entityBuilder)
        {
            // 获取实体构建器元数据
            var metadata = entityBuilder.Metadata;
            if (metadata.FindProperty(nameof(FullEntity.IsDeleted)) == null) return default;

            // 创建表达式元素
            var parameter = Expression.Parameter(metadata.ClrType, "u");
            var properyName = Expression.Constant(nameof(FullEntity.IsDeleted));
            var propertyValue = Expression.Constant(false);

            // 构建表达式 u => EF.Property<bool>(u, "IsDeleted") == false
            var expressionBody = Expression.Equal(Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(bool) }, parameter, properyName), propertyValue);
            var expression = Expression.Lambda(expressionBody, parameter);
            return expression;
        }

        #endregion 全局筛选器

        protected override void SaveChangesFailedEvent(DbContextErrorEventData eventData)
        {
            base.SaveChangesFailedEvent(eventData);
        }

        protected override void SavedChangesEvent(SaveChangesCompletedEventData eventData, int result)
        {
            base.SavedChangesEvent(eventData, result);
        }

        /// <summary>
        /// 重写保存之前事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result)
        {
            // 获取当前事件对应上下文
            var dbContext = eventData.Context;
            // 强制重新检查一边实体更改信息
            dbContext!.ChangeTracker.DetectChanges();

            // 通过请求中获取当前操作人
            var userId = App.HttpContext.GetValue<int>(ClaimConst.Claim_UserId);//
            var userName = App.HttpContext.GetValue<string>(ClaimConst.Claim_Name);//

            // 获取所有新增和更新的实体
            var entities = dbContext.ChangeTracker.Entries().Where(u =>

//u.Entity.GetType() != typeof(SysLogAudit) && u.Entity.GetType() != typeof(SysLogOp) && u.Entity.GetType() != typeof(SysLogVisit) && u.Entity.GetType() != typeof(SysLog) &&
(u.State == EntityState.Added || u.State == EntityState.Modified || u.State == EntityState.Deleted));

            //审计日志
            //AutidLog(eventData, userId, userName);

            #region 创建人、最后操作人

            {
                //// 获取所有新增和更新的实体
                //var entities = dbContext.ChangeTracker.Entries().Where(u => u.State == EntityState.Added || u.State == EntityState.Modified);

                //foreach (var entity in entities)
                //{
                //    switch (entity.State)
                //    {
                //        // 自动设置租户Id
                //        case EntityState.Added:
                //            entity.Property(nameof(CreateEntity.CreatorUserId)).CurrentValue = userId ?? 0;
                //            entity.Property(nameof(CreateEntity.CreatorUserName)).CurrentValue = userName;
                //            entity.Property(nameof(CreateEntity.CreationTime)).CurrentValue = DateTime.Now;
                //            break;
                //        // 排除租户Id
                //        case EntityState.Modified:
                //            entity.Property(nameof(Entity.TenantId)).IsModified = false;

                //            entity.Property(nameof(FullEntity.LastModifierUserId)).CurrentValue = userId ?? 0;
                //            entity.Property(nameof(FullEntity.LastModifierUserName)).CurrentValue = userName;
                //            entity.Property(nameof(FullEntity.LastModificationTime)).CurrentValue = DateTime.Now;

                //            break;
                //    }
                //}

                //子实体被修改的时候，去这里找旧的值，这样就不用去数据库再找一遍了
                //var deletedcache = entities.Where(d => d.State == EntityState.Deleted).ToDictionary(d => d.Entity.GetType().FullName + d.Property("Id").CurrentValue, d => d);
                foreach (var entity in entities)
                {
                    switch (entity.State)
                    {
                        case EntityState.Added:
                            {
                                //if (entity.Entity is not ICreate creationtimeentity) continue;
                                //if (!entity.Entity.GetType().IsSubclassOf(typeof(ICreate))) continue;
                                if (entity.Entity is ICreate creationtimeentity)
                                {
                                    //var creationtimeentity = entity as ICreate;
                                    //判断创建时间是否小于 定义的最小日期时间，如果是则设置为当前时间
                                    //主要是为了方便有特殊需求需要设置创建时间的情况
                                    if (creationtimeentity.CreationTime < minDateTimeOffset)
                                    {
                                        creationtimeentity.CreationTime = DateTimeOffset.Now;
                                    }
                                    creationtimeentity.CreatorUserId = userId;
                                    creationtimeentity.CreatorUserName = userName!;
                                }
                            }

                            break;

                        case EntityState.Modified:

                            {
                                if (entity.Entity is IDeleted deleted)
                                {
                                    //判断是否是软删除/假删除  如果是假删除 设置删除信息
                                    var isdeleted = entity.Property(nameof(IDeleted.IsDeleted)).CurrentValue;
                                    if ((bool)isdeleted == true)
                                    {
                                        deleted.DeletedTime = DateTimeOffset.Now;
                                        deleted.DeletedUserId = userId;
                                        deleted.DeletedUserName = userName;
                                    }
                                    else
                                    {
                                        //如果是更新，更新信息
                                        if (entity.Entity is IUpdate updatetimeentity)
                                        {
                                            updatetimeentity.UpdateTime = DateTimeOffset.Now;
                                            updatetimeentity.UpdateUserId = userId;
                                            updatetimeentity.UpdateUserName = userName;
                                        }
                                    }
                                }
                                else
                                {
                                    //如果是更新，更新信息
                                    if (entity.Entity is IUpdate updatetimeentity)
                                    {
                                        updatetimeentity.UpdateTime = DateTimeOffset.Now;
                                        updatetimeentity.UpdateUserId = userId;
                                        updatetimeentity.UpdateUserName = userName;
                                    }
                                }

                                if (entity.Entity is ICreate create)
                                {
                                    // 排除创建人
                                    entity.Property(nameof(FullEntity.CreatorUserId)).IsModified = false;
                                    entity.Property(nameof(FullEntity.CreatorUserName)).IsModified = false;
                                    // 排除创建日期
                                    entity.Property(nameof(FullEntity.CreationTime)).IsModified = false;
                                }
                            }
                            break;

                        case EntityState.Deleted:
                            // entity.Property(nameof(FullEntity.DeletionTime)).CurrentValue = DateTime.Now ;
                            //这个是物理删除，不做处理
                            break;
                    }
                }
            }

            #endregion 创建人、最后操作人

            base.SavingChangesEvent(eventData, result);
        }

        ///// <summary>
        ///// 审计日志
        ///// </summary>
        ///// <param name="eventData"></param>
        ///// <param name="entities"></param>
        ///// <param name="userId"></param>
        ///// <param name="userName"></param>
        //private void AutidLog(DbContextEventData eventData, int userId, string userName)
        //{
        //    #region 审计日志
        //    {
        //        try
        //        {
        //            var entities = eventData.Context.ChangeTracker.Entries().Where(u =>
        //          u.Entity.GetType() != typeof(SysLogAudit) && u.Entity.GetType() != typeof(SysLogOp) && u.Entity.GetType() != typeof(SysLogVisit) &&
        //          (u.State == EntityState.Added || u.State == EntityState.Modified || u.State == EntityState.Deleted || u.State == EntityState.Detached));

        //            // 获取所有更改，删除，新增的实体，但排除审计实体（避免死循环）
        //            //var entities = dbContext.ChangeTracker.Entries()
        //            //    .Where(u => u.Entity.GetType() != typeof(AutidLog) && (u.State == EntityState.Modified ||
        //            //                                                           u.State == EntityState.Deleted ||
        //            //                                                           u.State == EntityState.Added))
        //            //    .ToList();
        //            var autidlogs = new List<SysLogAudit>();
        //            var changecontent = new StringBuilder();
        //            // 获取所有已更改的实体
        //            foreach (var entity in entities)
        //            {
        //                // 获取实体类型
        //                var entityType = entity.Entity.GetType();

        //                // 获取所有实体有效属性，排除 [NotMapper] 属性
        //                var props = entity.OriginalValues.Properties;

        //                // 获取实体当前（现在）的值
        //                var currentValues = entity.CurrentValues;

        //                // 获取数据库中实体的值
        //                var databaseValues = entity.GetDatabaseValues();

        //                //获取主键的值
        //                var key = props.FirstOrDefault(o => o.IsPrimaryKey())?.Name;
        //                var keyvalue = currentValues?[key] ?? "";

        //                changecontent.Clear();//遍历前清空
        //                                      // 遍历所有属性
        //                foreach (var prop in props)
        //                {
        //                    // 获取属性名
        //                    var propName = prop.Name;
        //                    // 获取现在的实体值
        //                    var newValue = currentValues[propName];
        //                    object oldValue = null;
        //                    // 如果是新增数据，则 databaseValues 为空，所以需要判断一下
        //                    if (databaseValues != null)
        //                    {
        //                        oldValue = databaseValues[propName];
        //                    }
        //                    //if (newValue == oldValue) continue;
        //                    //if ( newValue.Equals(oldValue)) continue;
        //                    if (newValue == oldValue) continue;

        //                    changecontent.AppendLine($"{propName}: 【{oldValue?.ToString()}】 =>  【{newValue?.ToString()}】");
        //                }

        //                var autidlog = new SysLogAudit
        //                {
        //                    DataId = keyvalue.ToString(),
        //                    Table = entityType.Name, // 表名
        //                                             //Column = propName, // 更新的列
        //                                             //NewValue = newValue?.ToString(), // 新值
        //                                             //OldValue = oldValue?.ToString(), // 旧值
        //                    Content = changecontent.ToString(),
        //                    CreationTime = DateTime.Now, // 操作时间
        //                    CreatorUserId = userId, // 操作人
        //                    CreatorUserName = userName,
        //                    Operate = entity.State.GetEntityState() // 操作方式：新增、更新、删除
        //                };
        //                autidlogs.Add(autidlog);
        //            }
        //            // 插入审计日志表
        //            eventData.Context.Set<SysLogAudit>().AddRange(autidlogs);
        //        }
        //        catch (Exception ex)
        //        {
        //        }
        //    }

        //    #endregion 审计日志
        //}
    }
}